package com.boboPlanet.comm.rabbitmq.consume;

import com.boboPlanet.comm.context.BusinessThreadContextHolder;
import com.boboPlanet.comm.context.TraceIdContext;
import com.boboPlanet.comm.enums.PlanetCommCode;
import com.boboPlanet.comm.thread.ThreadMdcUtil;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.jetbrains.annotations.NotNull;
import org.slf4j.MDC;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;

/**
 * @Description: TODO
 * @Author: mis_wu
 * @Date: 2023/7/11
 * @Company xxx
 **/
@Component
@Aspect
@Slf4j
public class RabbitMqConsumeAspect {

    @Pointcut("@annotation(org.springframework.amqp.rabbit.annotation.RabbitListener)")
    public void mqListenerPointcut(){}

    @Before(value = "mqListenerPointcut() && args(message,channel,tag)", argNames = "joinPoint,message,channel,tag")
    public void before(JoinPoint joinPoint, @NotNull Message message, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long tag) throws IOException {
        Object target = joinPoint.getTarget();
        log.info("into rabbitmq after aop,current object is: {}",target);

        //判断是否认证授权
        Boolean isAuth = (Boolean) message.getMessageProperties().getHeaders().get(PlanetCommCode.MQ_HEADER_AUTHORIZATION.getCode());
        if (Boolean.FALSE.equals(isAuth)){
            return;
        }

        //注入线程上下文信息
        byte[] capture = (byte[]) message.getMessageProperties().getHeaders().get(PlanetCommCode.MQ_HEADER_CAPTURE.getCode());

        String traceId = (String) message.getMessageProperties().getHeaders().get(PlanetCommCode.COMM_LOG_KEY.getCode());

        //PlanetMqMsg mqMsg = PlanetMqMsg.deserialize(new String(message.getBody()));

        if (StringUtils.isBlank(traceId)){
            traceId = ThreadMdcUtil.setTraceId();
        }

        //todo 判断不需要校验用户信息的路径，直接通过即可

        ThreadMdcUtil.setTraceId(traceId);

        MDC.put(PlanetCommCode.COMM_LOG_KEY.getCode(),traceId);

        TraceIdContext.setTraceId(traceId);

        ByteArrayInputStream bis = new ByteArrayInputStream(capture);

        ObjectInput in = new ObjectInputStream(bis);
        try {
            //确保 BusinessThreadContextHolder 实现了序列化
            BusinessThreadContextHolder holder = (BusinessThreadContextHolder) in.readObject();
            holder.inject();
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }finally {
            BusinessThreadContextHolder.clear();
        }
    }

    @After("mqListenerPointcut()")
    public void doAfter(){
        BusinessThreadContextHolder.clear();
    }
}
